/*
 * data_table.cpp
 *
 *  Created on: 2008-8-20
 *      Author: fanliangliang
 */

#include "data_table.h"
#include <algorithm>
#include <iomanip>

BEGIN_NAMESPACE_TOXIC

using namespace std;

ostream& operator<<(ostream& ostrm, const DataTable& table) {

	table.printHorizontalLine(ostrm);
	table.printHeader(ostrm);
	table.printHorizontalLine(ostrm);
	size_t rowCount = table.rows();
	if (rowCount != 0) {
		bool rowSeparatorEnabled = table.rowSeparatorEnabled();
		for (size_t row = 0; row < rowCount - 1; ++row) {
			table.printRow(row, ostrm);
			if (rowSeparatorEnabled) {
				table.printHorizontalLine(ostrm);
			}
		}
		table.printRow(rowCount - 1, ostrm);
	}
	table.printHorizontalLine(ostrm, false);

	return ostrm;
}

DataTable::DataTable()
:_rowSeparatorEnabled(false) {
}

DataTable::~DataTable() {
	size_t rowCount = rows();
	for (size_t row = 0; row < rowCount; ++row) {
		delete _data[row];
	}

	size_t colCount = columns();
	for (size_t col = 0; col < colCount; ++col) {
		delete _styles[col];
	}
}

bool DataTable::rowSeparatorEnabled() const {
	return _rowSeparatorEnabled;
}

void DataTable::setRowSeparatorEnabled(bool enable) {
	_rowSeparatorEnabled = enable;
}

size_t DataTable::maxColumnWidth(size_t col) const {
	return columnAt(col).maxWidth();
}

size_t DataTable::idealColumnWidth(size_t col) const {

	if (empty()) {
		return _styles[col]->headerWidth();
	}

	return max(maxColumnWidth(col), _styles[col]->headerWidth());
}

void DataTable::printHorizontalLine(ostream& ostrm, bool endline /*= true*/) const {

	ostrm << setfill('-');
	size_t colCount = columns();
	for (size_t col = 0; col < colCount; ++col) {
		size_t width = idealColumnWidth(col) + 2;
		ostrm << "+" << setw(width) << "-";
	}
	ostrm << setfill(' ') << "+";
	if (endline) {
		ostrm << endl;
	}
}

static ostream& operator<<(ostream& ostrm, const any& value) {
	return value.print(ostrm);
}

void DataTable::printRow(size_t row, ostream& ostrm) const {

	size_t colCount = columns();
	for (size_t col = 0; col < colCount; ++col) {
		AlignType align = _styles[col]->contentAlign();
		size_t maxColWidth = maxColumnWidth(col);
		size_t idealWidth = idealColumnWidth(col);
		size_t nEmpty = 0, nLeft = 0, nRight = 0;
		if (maxColWidth < idealWidth) {
			nEmpty = idealWidth - maxColWidth;
			nLeft = nEmpty / 2;
			nRight = nEmpty - nLeft;
			if (align == ALIGN_LEFT) {
				idealWidth = idealWidth - nLeft;
				ostrm << "| ";
				if (nLeft > 0)
					ostrm << setw(nLeft) << " ";

				ostrm << left;
				ostrm << setw(idealWidth) << at(row, col) << " ";

			} else if (align == ALIGN_RIGHT) {
				idealWidth = idealWidth - nRight;
				ostrm << "| ";
				ostrm << right;
				ostrm << setw(idealWidth) << at(row, col) << " ";

				if (nRight > 0)
					ostrm << setw(nRight) << " ";

			} else { // align == ALIGN_CENTER
				any& item = at(row, col);
				nEmpty = idealWidth - item.width();
				nLeft = nEmpty / 2;
				nRight = nEmpty - nLeft;
				idealWidth = idealWidth - nRight;
				ostrm << right;
				ostrm << "| "
				<< setw(idealWidth) << item
				<< setw(nRight + 1) << " ";
			}
		} else {
			if (align == ALIGN_LEFT) {
				ostrm << left;
				ostrm << "| "
				<< setw(idealWidth) << at(row, col) << " ";
			} else if (align == ALIGN_RIGHT) {
				ostrm << right;
				ostrm << "| "
				<< setw(idealWidth) << at(row, col) << " ";
			} else { // align == ALIGN_CENTER
				any& item = at(row, col);
				nEmpty = idealWidth - item.width();
				nLeft = nEmpty / 2;
				nRight = nEmpty - nLeft;
				idealWidth = idealWidth - nRight;
				ostrm << right;
				ostrm << "| "
				<< setw(idealWidth) << item
				<< setw(nRight + 1) << " ";
			}
		}
	}
	ostrm << "|" << endl;
}

void DataTable::printHeader(ostream& ostrm) const {

	size_t colCount = columns();
	for (size_t col = 0; col < colCount; ++col) {
		AlignType align = _styles[col]->headerAlign();
		size_t headerWidth = _styles[col]->headerWidth();
		size_t idealWidth = idealColumnWidth(col);
		size_t nEmpty = 0, nLeft = 0, nRight = 0;
		if (headerWidth < idealWidth) {
			if (align == ALIGN_LEFT) {
				ostrm << left;
				ostrm << "| "
				<< setw(idealWidth) << _styles[col]->header() << " ";
			} else if (align == ALIGN_RIGHT) {
				ostrm << right;
				ostrm << "| "
				<< setw(idealWidth) << _styles[col]->header() << " ";
			} else { // align == ALIGN_CENTER
				nEmpty = idealWidth - headerWidth;
				nLeft = nEmpty / 2;
				nRight = nEmpty - nLeft;
				idealWidth = idealWidth - nRight;
				ostrm << right;
				ostrm << "| "
				<< setw(idealWidth) << _styles[col]->header()
				<< setw(nRight + 1) << " ";
			}
		} else {
			ostrm << "| " << _styles[col]->header() << " ";
		}
	}
	ostrm << "|" << endl;
}

END_NAMESPACE_TOXIC
